#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from stuapi.models import Student

"""
serializers 是drf提供给开发者调用的序列化器模块
声明了所有序列化器的基类
Serializer 序列化基类，drf中所有的序列化器类都继承与Serializer
ModelSerializer 模型序列化器基类，是序列化器基类的子类，在工作中除了Serializer基类最常用的

"""


# 普通serializers序列器
class Student1Serializer_one(serializers.Serializer):
    """学生信息序列化器"""

    # 1、转换的字段声明
    # 客户端字段 = serializers.字段类型(选项=选项值)
    id = serializers.IntegerField()
    name = serializers.CharField()
    sex = serializers.BooleanField()
    age = serializers.IntegerField()
    description = serializers.CharField()

    # 2、如果当前序列化器继承的是ModelSerializer，则需要声明调用的模型信息
    # class Meta:
    #     model = "模型"
    #     fields = ["字段1", "字段2"]

    # 3、验证代码的对象方法
    # def validate(self, attrs):  # 名称固定
    #     pass
    #     return attrs

    # def validate_<字段名>(self, data):方法名的格式必须以validate_<字段名>为名称，不然序列化不认识
    #     pass
    #     return data

    # 4、模型操作方法
    # def create(self, validated_data): # 完成添加操作，添加数据后，自动实现了从字典变成对象过程
    #     pass
    #
    # def update(self, instance, validated_data):# 完成添加修改，添加数据后，自动实现了从字典变成对象过程
    #     pass


def check_age(data):
    """外部验证函数"""
    if data > 30:
        raise serializers.ValidationError(detail="年纪不能大于30", code="check_age")
    # 验证完成后务必返回结果，否则验证结果中没有返回结果
    return data


class Student1Serializer_two(serializers.Serializer):
    """学生信息序反列化器"""

    # 1、转换的字段声明
    id = serializers.IntegerField(read_only=True)  # 反序列化阶段不会要求id字段
    name = serializers.CharField(required=True)  # 必填项 required=True
    sex = serializers.BooleanField(default=True)  # 当用户不填写是给默认值
    age = serializers.IntegerField(max_value=100, min_value=0, error_messages={
        "min_value": "The Age Filed Must Be 0<= age <=100",
        "max_value": "The Age Filed Must Be age <=100",  # 自定义返回错误信息
    }, validators=[check_age])  # 反序列化值的值必须是 0<=age<=100
    description = serializers.CharField(allow_null=True, allow_blank=True)  # 允许服务端不填写(None)或传值为""

    # 2、如果当前序列化器继承的是ModelSerializer，则需要声明调用的模型信息
    # class Meta:
    #     model = "模型"
    #     fields = ["字段1", "字段2"]

    # 3、验证代码的对象方法
    # def validate(self, attrs):  # 名称固定
    #     pass
    #     return attrs

    # def validate_<字段名>(self, data):方法名的格式必须以validate_<字段名>为名称，不然序列化不认识
    #     pass
    #     return data
    def validate_name(self, data):
        """验证当个字段,validate开头的方法会自动被is_valid调用"""
        if data in ["path", "django"]:
            # 在序列化中，验证失败可以通过抛出异常的方式来告知is_valid
            raise serializers.ValidationError(detail="学生姓名中不能是python或django", code="name")
        # 验证成功必须返回数据，否则最终结果不会出现data数据
        return data

    def validate(self, attrs):
        """验证来自客户端多少字段,类似于会员注册，密码和确认密码就只能在这边校验
            validate 固定方法名
            attrs: 序列化实例化时的data数据
        """
        # 301班只能有女生，不能加入其他男生
        if attrs["age"] == 30 and attrs["sex"]:
            raise serializers.ValidationError(detail="不能为30岁的男生")
        return attrs

    # 4、模型操作方法
    def create(self, validated_data):  # 完成添加操作，添加数据后，自动实现了从字典变成对象过程
        """添加数据，方法名固定且参数固定validated_data是验证成功后的结果"""
        student = Student.objects.create(**validated_data)  # 验证后的数据
        return student

    #
    def update(self, instance, validated_data):  # 完成添加修改，添加数据后，自动实现了从字典变成对象过程
        """更新数据操作，方法名固定，参数固定
        instance:实例化序列器对象时，必须传入的模型对象
        """
        # instance.name = validated_data["name"]
        # instance.sex = validated_data["sex"]
        # instance.age = validated_data["age"]
        # instance.description = validated_data["description"]
        # instance.save()  # 这是模型的save方法，和序列化中的save方法不是同一个方法
        for key, value in validated_data.items():
            print(getattr(instance, key))  # getattr 获取属性的值
            setattr(instance, key, value)  # 更改instance中的属性，如果不存在则创建

        instance.save()
        return instance


# 模型序列化
class StudentModelSerializer(serializers.ModelSerializer):
    """学生信息序列化器"""
    nickname = serializers.CharField(read_only=True)  # 可以额外定义模型外的字段

    # 1、 转换字段声明
    # 2、Meta类，必须给Meta声明模型类，
    class Meta:
        model = Student  # 必填
        fields = ["id", "name", "age", "classmate", "sex", "nickname"]  # 必填,可以是"__all__" 字符串或列表/元祖
        # exclude = [] # 与fields相反
        read_only_fields = ["classmate"]  # 选填，只读字段列表，设置在这里的字段只会在序列化阶段采用，在这里写入的字段，客户端可以不传该字段也不会报错,如果是添加操作也不会返回数据给客户端
        extra_kwargs = {
            "age": {"max_value": 28, "error_messages": {"max_value": "年龄必须小于28"}},  # 定义额外约束
        }  # 选填，额外选项声明，

    # 3、校验数据方法
    def create(self, validated_data):
        # 密码加密
        # validated_data["password"] = make_password(validated_data["password"])
        super().create(validated_data)
        return validated_data

    # 4、模型类方法
